/**
 *
 * 2007-11-4 下午03:04:30
 * @author xuhuan
 */

package edu.ccut.saturn.studio.action;

import java.io.File;
import java.util.EventObject;
import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.parts.ScrollableThumbnail;
import org.eclipse.draw2d.parts.Thumbnail;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.dnd.TemplateTransferDragSourceListener;
import org.eclipse.gef.dnd.TemplateTransferDropTargetListener;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.requests.CreationFactory;
import org.eclipse.gef.requests.SimpleFactory;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.palette.PaletteViewer;
import org.eclipse.gef.ui.palette.PaletteViewerProvider;
import org.eclipse.gef.ui.parts.ContentOutlinePage;
import org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette;
import org.eclipse.gef.ui.parts.GraphicalViewerKeyHandler;
import org.eclipse.gef.ui.parts.TreeViewer;
import org.eclipse.jdt.internal.core.JarEntryFile;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.TransferDropTargetListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.ui.views.navigator.LocalSelectionTransfer;
import org.w3c.dom.Document;

import edu.ccut.saturn.studio.Activator;
import edu.ccut.saturn.studio.logic.ShapesPlugin;
import edu.ccut.saturn.studio.logic.contextaction.Change;
import edu.ccut.saturn.studio.logic.contextaction.CopyAction;
import edu.ccut.saturn.studio.logic.contextaction.OpenLogicAction;
import edu.ccut.saturn.studio.logic.contextaction.PasteAction;
import edu.ccut.saturn.studio.logic.model.Shape;
import edu.ccut.saturn.studio.logic.model.ShapesDiagram;
import edu.ccut.saturn.studio.logic.model.drop.DropHandler;
import edu.ccut.saturn.studio.logic.model.drop.DropHandlerFactory;
import edu.ccut.saturn.studio.logic.model.drop.action.ActionDropHandleFactory;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnComponentNode;
import edu.ccut.saturn.studio.logic.model.saturn.action.SaturnInformationNodeInAction;
import edu.ccut.saturn.studio.logic.parts.ShapesEditPartFactory;
import edu.ccut.saturn.studio.logic.parts.ShapesTreeEditPartFactory;

public class ActionEditor extends GraphicalEditorWithFlyoutPalette {

	public static final String ID = "Action Editor";
	
	private ShapesDiagram diagram;

	private static PaletteRoot PALETTE_MODEL;

	private Point mousePoint;

	public ActionEditor(List<Shape> shapes, Document document) {
		diagram = new ShapesDiagram(this, document);
		for (Shape shape : shapes) {
			this.diagram.getShapes().add(shape);
			shape.setParent(diagram);
			shape.setDocument(document);
		}

		setEditDomain(new DefaultEditDomain(this));
	}

	public ShapesDiagram getDiagram() {
		return diagram;
	}

	protected void configureGraphicalViewer() {
		super.configureGraphicalViewer();

		GraphicalViewer viewer = getGraphicalViewer();
		viewer.setEditPartFactory(new ShapesEditPartFactory());
		viewer.setRootEditPart(new ScalableFreeformRootEditPart());
		viewer.setKeyHandler(new GraphicalViewerKeyHandler(viewer));
		viewer.addSelectionChangedListener(new ISelectionChangedListener() {
			public void selectionChanged(SelectionChangedEvent event) {
				updateActions(getSelectionActions());
			}
		});
		viewer.setKeyHandler(new GraphicalViewerKeyHandler(viewer));
		// configure the context menu provider
		ContextMenuProvider cmProvider = new ActionEditorContextMenuProvider(
				viewer, getActionRegistry());
		viewer.setContextMenu(cmProvider);
		getSite().registerContextMenu(cmProvider, viewer);
	}

	public void commandStackChanged(EventObject event) {
		firePropertyChange(IEditorPart.PROP_DIRTY);
		super.commandStackChanged(event);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#createPaletteViewerProvider()
	 */
	protected PaletteViewerProvider createPaletteViewerProvider() {
		return new PaletteViewerProvider(getEditDomain()) {
			protected void configurePaletteViewer(PaletteViewer viewer) {
				super.configurePaletteViewer(viewer);
				viewer
						.addDragSourceListener(new TemplateTransferDragSourceListener(
								viewer));
			}
		};
	}

	/**
	 * Create a transfer drop target listener. When using a
	 * CombinedTemplateCreationEntry tool in the palette, this will enable model
	 * element creation by dragging from the palette.
	 * 
	 * @see #createPaletteViewerProvider()
	 */
	private TransferDropTargetListener createTransferDropTargetListener() {
		return new TemplateTransferDropTargetListener(getGraphicalViewer()) {
			@SuppressWarnings("unchecked")
			protected CreationFactory getFactory(Object template) {
				return new SimpleFactory((Class) template);
			}
		};
	}

	public void doSave(IProgressMonitor monitor) {
		getCommandStack().markSaveLocation();
	}

	public void doSaveAs() {
		getCommandStack().markSaveLocation();
	}

	@SuppressWarnings("unchecked")
	public Object getAdapter(Class type) {
		if (type == IContentOutlinePage.class)
			return new OutlinePage(new TreeViewer());
		return super.getAdapter(type);
	}

	protected PaletteRoot getPaletteRoot() {
		if (PALETTE_MODEL == null)
			PALETTE_MODEL = ActionEditorPaletteFactory.createPalette();
		return PALETTE_MODEL;
	}

	/**
	 * Set up the editor's inital content (after creation).
	 * 
	 * @see org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#initializeGraphicalViewer()
	 */
	protected void initializeGraphicalViewer() { // 初始化调色板
		super.initializeGraphicalViewer();
		GraphicalViewer viewer = getGraphicalViewer();

		viewer.getControl().addMouseMoveListener(new MouseMoveListener() {
			public void mouseMove(MouseEvent e) {
				mousePoint = new Point(e.x, e.y);
			}
		});

		viewer.setContents(this.diagram); // set the contents of this editor

		// listen for dropped parts
		viewer.addDropTargetListener(createTransferDropTargetListener());
		viewer.addDropTargetListener(createTransferDropTargetListener1());
	}

	private TransferDropTargetListener createTransferDropTargetListener1() {
		return new TemplateTransferDropTargetListener(getGraphicalViewer()) {
			// TODO: CCUT
			@Override
			protected void setTransfer(Transfer xfer) {
				super.setTransfer(LocalSelectionTransfer.getInstance());
			}

			@SuppressWarnings("restriction")
			@Override
			protected void handleDrop() {
//				IPath workspacePath = ResourcesPlugin.getWorkspace().getRoot()
//						.getLocation();

				LocalSelectionTransfer transfer = (LocalSelectionTransfer) getTransfer();

				TreeSelection selection = (TreeSelection) transfer
						.getSelection();
				Object firstElement = selection.getFirstElement();

				Shape shape = null;

				if (firstElement instanceof IResource) {
					IPath projectFilePath = ((IResource) firstElement)
							.getFullPath();
					String projectFullPath = getProjectFullPath(projectFilePath);
					DropHandlerFactory dropHandlerFactory = new ActionDropHandleFactory();
					DropHandler drophandler = dropHandlerFactory
							.getShapeHandler(projectFilePath.toString());
//					IPath fullPath = workspacePath.append(projectFilePath);
//					String fullPathStr = fullPath.toOSString().replaceAll("/",
//							"\\\\");
					if (drophandler != null ) {
						shape = drophandler.getShape(projectFullPath,
								getProject(projectFilePath));
					}
				} else if (firstElement instanceof JarEntryFile) {
					String jarName = ((JarEntryFile) firstElement)
							.getFullPath().toString();
					DropHandlerFactory dropHandlerFactory = new ActionDropHandleFactory();
					DropHandler drophandler = (DropHandler) dropHandlerFactory
							.getShapeHandler(jarName);
					if (drophandler != null ) {
						try {
							shape = drophandler
									.getShape((JarEntryFile) firstElement);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}

				if (shape != null) {
					shape.setId(getDiagram().getNextValidShapeId());
					shape.setLocation(getDropLocation());
					getDiagram().addShape(shape);
				}

			}

			@Override
			public void drop(DropTargetEvent event) {
				super.drop(event);
				event.detail = DND.DROP_COPY;

				if (LocalSelectionTransfer.getInstance().isSupportedType(
						event.currentDataType)) {
				}
			}
		};
	}

	public boolean isSaveAsAllowed() {
		return true;
	}

	protected void setInput(IEditorInput input) {
		super.setInput(input);

	}

	protected void createActions() {
		super.createActions();
		ActionRegistry register = getActionRegistry();
		IAction action = new OpenLogicAction((IWorkbenchPart) this);
		action.setId(OpenLogicAction.ACTION_OPEN_MODEL);
		register.registerAction(action);
		getSelectionActions().add(action.getId());

		@SuppressWarnings("unchecked")
		IAction copyAction = new CopyAction((IWorkbenchPart) this);
		action.setId(ActionFactory.COPY.getId());
		register.registerAction(copyAction);
		getSelectionActions().add(copyAction.getId());

		@SuppressWarnings("unchecked")
		IAction pasteAction = new PasteAction((IWorkbenchPart) this);
		action.setId(ActionFactory.PASTE.getId());
		register.registerAction(pasteAction);
		getSelectionActions().add(pasteAction.getId());

		IAction change = new Change((IWorkbenchPart) this);
		action.setId(Change.ID);
		register.registerAction(change);
		getSelectionActions().add(change.getId());
	}
	

	private String getProjectFullPath(IPath projectFilePath) {
		String projectFilePathString = projectFilePath.toFile().toString();
		String projectName = getProjectName(projectFilePath);
		projectFilePathString = "\\" + projectFilePathString.substring(projectFilePathString.indexOf("\\", 2), projectFilePathString.length());
//		projectFilePathString = projectFilePathString.replace(projectName, "");
		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(
				projectName);
		return project.getFile(projectFilePathString).getLocation()
				.toOSString();

	}
	
	private String getProjectName(IPath projectFilePath){
		String projectFilePathString = projectFilePath.toFile().toString();
		String projectNamePart1 = projectFilePathString.substring(1,projectFilePathString.length());
		String projectName = projectNamePart1.substring(0,projectNamePart1.indexOf(File.separator));
		projectFilePathString = null;
		projectNamePart1 = null;
		return projectName;
	}

	private IProject getProject(IPath projectFilePath) {
		String projectFilePathString = projectFilePath.toFile().toString();
		String projectName = getProjectName(projectFilePath);
		projectFilePathString = projectFilePathString.replace(projectName, "");
		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(
				projectName);
		return project;

	}
	
	public String getFileName(List<Shape> shapes){
		for(Shape shape :shapes){
			if(shape instanceof SaturnInformationNodeInAction){
				String fileName = shape.findTheProject().getName()+"::"+shape.getKey();
				return fileName;
			}
		}
		return "";
	}

	/**
	 * Creates an outline pagebook for this editor.
	 */
	// TODO:TEST OUTLINE
	private OutlinePage outlinePage;

	class OutlinePage extends ContentOutlinePage implements IAdaptable {

		private PageBook pageBook;

		private Control outline;

		private Canvas overview;

		private IAction showOutlineAction, showOverviewAction;

		static final int ID_OUTLINE = 0;

		static final int ID_OVERVIEW = 1;

		private Thumbnail thumbnail;

		private DisposeListener disposeListener;

		public OutlinePage(EditPartViewer viewer) {
			super(viewer);
		}

		public void createControl(Composite parent) {
			pageBook = new PageBook(parent, SWT.NONE);
			outline = getViewer().createControl(pageBook);
			overview = new Canvas(pageBook, SWT.NONE);
			pageBook.showPage(outline);
			configureOutlineViewer();
			hookOutlineViewer();
			initializeOutlineViewer();
		}

		protected void configureOutlineViewer() {
			getViewer().setEditDomain(getEditDomain());
			getViewer().setEditPartFactory(new ShapesTreeEditPartFactory());
			ContextMenuProvider provider = new ActionEditorContextMenuProvider(
					getViewer(), getActionRegistry());
			getViewer().setContextMenu(provider);
			IToolBarManager tbm = getSite().getActionBars().getToolBarManager();
			showOutlineAction = new Action() {
				public void run() {
					showPage(ID_OUTLINE);
				}
			};
			showOutlineAction
					.setImageDescriptor(ImageDescriptor.createFromFile(
//							ShapesPlugin.class, IconNames.SATURN_OUTLINE)); //$NON-NLS-1$
							ShapesPlugin.class, Activator.SATURN_OUTLINE)); //$NON-NLS-1$
			tbm.add(showOutlineAction);
			showOverviewAction = new Action() {
				public void run() {
					showPage(ID_OVERVIEW);
				}
			};
			showOverviewAction.setImageDescriptor(ImageDescriptor
					.createFromFile(ShapesPlugin.class,
//							IconNames.SATURN_OVERVIEW));
							Activator.SATURN_OUTLINE));
			tbm.add(showOverviewAction);
			showPage(ID_OUTLINE);
		}

		protected void hookOutlineViewer() {
			getSelectionSynchronizer().addViewer(getViewer());
		}

		protected void initializeOverview() {
			LightweightSystem lws = new LightweightSystem(overview);
			RootEditPart rep = getGraphicalViewer().getRootEditPart();
			if (rep instanceof ScalableFreeformRootEditPart) {
				ScalableFreeformRootEditPart root = (ScalableFreeformRootEditPart) rep;
				thumbnail = new ScrollableThumbnail((Viewport) root.getFigure());
				thumbnail.setBorder(new MarginBorder(3));
				thumbnail.setSource(root
						.getLayer(LayerConstants.PRINTABLE_LAYERS));
				lws.setContents(thumbnail);
				disposeListener = new DisposeListener() {
					public void widgetDisposed(DisposeEvent e) {
						if (thumbnail != null) {
							thumbnail.deactivate();
							thumbnail = null;
						}
					}
				};
				getEditor().addDisposeListener(disposeListener);
			}
		}

		public void init(IPageSite pageSite) {
			super.init(pageSite);
			ActionRegistry registry = getActionRegistry();
			IActionBars bars = pageSite.getActionBars();
			String id = ActionFactory.UNDO.getId();
			bars.setGlobalActionHandler(id, registry.getAction(id));
			id = ActionFactory.REDO.getId();
			bars.setGlobalActionHandler(id, registry.getAction(id));
			id = ActionFactory.DELETE.getId();
			bars.setGlobalActionHandler(id, registry.getAction(id));
			bars.updateActionBars();
		}

		public void dispose() {
			unhookOutlineViewer();
			if (thumbnail != null) {
				thumbnail.deactivate();
				thumbnail = null;
			}
			super.dispose();
			ActionEditor.this.outlinePage = null;
			outlinePage = null;
		}

		public Object getAdapter(Class type) {
			return null;
		}

		public Control getControl() {
			return pageBook;
		}

		protected void initializeOutlineViewer() {
			setContents(getDiagram());
		}

		public void setContents(Object contents) {
			getViewer().setContents(contents);
		}

		protected void showPage(int id) {
			if (id == ID_OUTLINE) {
				showOutlineAction.setChecked(true);
				showOverviewAction.setChecked(false);
				pageBook.showPage(outline);
				if (thumbnail != null)
					thumbnail.setVisible(false);
			} else if (id == ID_OVERVIEW) {
				if (thumbnail == null)
					initializeOverview();
				showOutlineAction.setChecked(false);
				showOverviewAction.setChecked(true);
				pageBook.showPage(overview);
				thumbnail.setVisible(true);
			}
		}

		protected void unhookOutlineViewer() {
			getSelectionSynchronizer().removeViewer(getViewer());
			if (disposeListener != null && getEditor() != null
					&& !getEditor().isDisposed())
				getEditor().removeDisposeListener(disposeListener);
		}

	}
	
	protected FigureCanvas getEditor() {
		return (FigureCanvas) getGraphicalViewer().getControl();
	}

	public Point getMousePoint() {
		return mousePoint;
	}

}
